#include "GraphDrawer.h"

int GraphDrawer::debug = 0;

GraphDrawer::GraphDrawer(){
	initImages();
	yMin = 0.0;
	xMin = 0.0;
	yMax = 0.0;
	xMax = 0.0;
}

GraphDrawer::~GraphDrawer(){
	SDL_Quit();
}

int GraphDrawer::makeTransparent(SDL_Surface* surface, Color c){
	  return SDL_SetColorKey(surface, SDL_SRCCOLORKEY, SDL_MapRGB(surface->format, c.getR(), c.getG(), c.getR()));
}

SDL_Surface* GraphDrawer::loadBMP(const char* fileName){
	SDL_Surface* bmp = NULL;
	bmp = SDL_LoadBMP(fileName);

	if (bmp == NULL){
		std::string s("..\\");
		s.append(fileName);
		bmp = SDL_LoadBMP(s.c_str());
	}

	if (bmp == NULL){
		std::string s("C:\\");
		s.append(fileName);
		bmp = SDL_LoadBMP(s.c_str());
	}
	return bmp;
}

int GraphDrawer::initImages(){
	avenue = loadBMP("avenue.bmp");
	avenueV = loadBMP("avenueV.bmp");
	street = loadBMP("street.bmp");
	streetV = loadBMP("streetV.bmp");
	highway = loadBMP("highway.bmp");
	highwayV = loadBMP("highwayV.bmp");

	crossroads = loadBMP("crossroads.bmp");
	street23 = loadBMP("street233.bmp");

	hotel = loadBMP("hotel.bmp");
	restaurant = loadBMP("restaurant.bmp");
	comisaria = loadBMP("comisaria.bmp");
	escuela = loadBMP("escuela.bmp");
	hospital = loadBMP("hospital.bmp");

	originDot = loadBMP("origin.bmp");
	destinyDot = loadBMP("destiny.bmp");

	car = loadBMP("ferrari.bmp");
	grass = loadBMP("grass.bmp");

	Color c = c.white;
	makeTransparent(avenue, c);
	makeTransparent(avenueV, c);
	makeTransparent(street, c);
	makeTransparent(streetV, c);
	makeTransparent(street23, c);
	makeTransparent(highway, c);
	makeTransparent(crossroads, c);

	makeTransparent(hotel,c);
	makeTransparent(restaurant,c);
	makeTransparent(comisaria,c);
	makeTransparent(escuela,c);
	makeTransparent(hospital,c);

	makeTransparent(originDot,c);
	makeTransparent(destinyDot,c);

	return 0;
}

void GraphDrawer::drawIMG(SDL_Surface *img, int x, int y, SDL_Surface *background){
  SDL_Rect dest;
  dest.x = x;
  dest.y = y;
//  SDL_SetColorKey(img, SDL_SRCCOLORKEY, SDL_MapRGB(img->format, 255, 255, 255));
  SDL_BlitSurface(img, NULL, background, &dest);
}

void GraphDrawer::drawIMG(SDL_Surface *src, int xSrc, int ySrc, int wSrc, int hSrc, int xDest, int yDest, SDL_Surface *dest){
  SDL_Rect rectDest;
  rectDest.x = xDest;
  rectDest.y = yDest;

  SDL_Rect rectSrc;
  rectSrc.x = xSrc;
  rectSrc.y = ySrc;
  rectSrc.w = wSrc;
  rectSrc.h = hSrc;
//  SDL_SetColorKey(src, SDL_SRCCOLORKEY, SDL_MapRGB(src->format, 255, 255, 255));

  SDL_BlitSurface(src, &rectSrc, dest, &rectDest);
}

void GraphDrawer::drawPixel(SDL_Surface *screen, int x, int y, Uint8 R, Uint8 G, Uint8 B){
	  Uint32 color = SDL_MapRGB(screen->format, R, G, B);
	  drawPixel(screen, x, y, color);
}

void GraphDrawer::drawPixel(SDL_Surface *screen, int x, int y, Uint32 color){
  switch (screen->format->BytesPerPixel)
  {
    case 1: // 8-bpp
      {
        Uint8 *bufp;
        bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;
        *bufp = color;
      }
      break;
    case 2: // 15-bpp - 16-bpp
      {
        Uint16 *bufp;
        bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x;
        *bufp = color;
      }
      break;
    case 3: // 24-bpp
      {
        Uint8 *bufp;
        bufp = (Uint8 *)screen->pixels + y*screen->pitch + x * 3;
        if(SDL_BYTEORDER == SDL_LIL_ENDIAN)
        {
          bufp[0] = color;
          bufp[1] = color >> 8;
          bufp[2] = color >> 16;
        } else {
          bufp[2] = color;
          bufp[1] = color >> 8;
          bufp[0] = color >> 16;
        }
      }
      break;
    case 4: // 32-bpp
      {
        Uint32 *bufp;
		bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;
		*bufp = color;
      }
      break;
  }
}

void GraphDrawer::drawPixel(SDL_Surface *screen, int x, int y, Color c){
	drawPixel(screen, x, y, c.getR(), c.getG(), c.getB());
}

void GraphDrawer::lock(SDL_Surface *screen){
  if ( SDL_MUSTLOCK(screen) )
  {
    if ( SDL_LockSurface(screen) < 0 )
    {
      return;
    }
  }
}

void GraphDrawer::unlock(SDL_Surface *screen){
  if ( SDL_MUSTLOCK(screen) )
  {
    SDL_UnlockSurface(screen);
  }
}

void GraphDrawer::fillSurface(SDL_Surface *screen, Color c){
	lock(screen);
	for(int x=0;x<screen->w;x++)
	{
	  for(int y=0;y<screen->h;y++)
	  {
	    drawPixel(screen, x,y,c);
	  }
	}
	unlock(screen);
	SDL_Flip(screen);
}

void GraphDrawer::fillSurfaceWithTexture(SDL_Surface* screen, SDL_Surface* texture) {
	int x = 0;
	lock(screen);
	for (x = 0; x < (int)(screen->h / texture->h); x++) {
		drawSpriteH(texture, 0, texture->h * x, screen->w, texture->h, screen);
	}
	if (screen->h % texture->h != 0) {
		drawSpriteH(texture, 0, texture->h * x, screen->w, texture->h - (int)(screen->h / texture->h), screen);
	}
}

void GraphDrawer::drawHLine(SDL_Surface *screen, int leftmost, int rightmost, int y, Color c){
	int begin = leftmost;
	int end = rightmost;
	if (rightmost < leftmost){
		begin = rightmost;
		end = leftmost;
	}

	for (int x = begin; x < end; x++){
		drawPixel(screen, x, y, c);
	}
	SDL_Flip(screen);
}

void GraphDrawer::drawSpriteV(SDL_Surface* sprite, int x, int y, int w, int h, SDL_Surface* backgroud){
	// TODO Verificar esto...
	int spriteW = sprite->w;
	int spriteH = sprite->h;
	int mod = h % spriteH;
	int q = h / spriteH;
	int i;

	for (i = 0; i < q; i++){
		drawIMG(sprite, 0, 0, spriteW, spriteH, x, y + (i * spriteH), backgroud);
	}

	if (mod > 0){
		drawIMG(sprite, 0, 0, spriteW, mod, x, y + (i * spriteH), backgroud);
	}
	SDL_Flip(backgroud);
}

void GraphDrawer::drawSpriteH(SDL_Surface* sprite, int x, int y, int w, int h, SDL_Surface* backgroud){
	// TODO Verificar esto...
	int spriteW = sprite->w;
	int spriteH = sprite->h;
	int mod = w % spriteW;
	int q = w / spriteW;
	int i;

	for (i = 0; i < q; i++){
		drawIMG(sprite, 0, 0, spriteW, spriteH, x + (i*spriteW), y, backgroud);
	}

	if (mod > 0){
		drawIMG(sprite, 0, 0, mod, spriteH, x + (i*spriteW), y, backgroud);
	}
	SDL_Flip(backgroud);
}

int GraphDrawer::findXY(int x1, int y1, int x2, int y2, int* xo, int* xf, int* yo, int* yf){
	float dy = y2 - y1;
	float dx = x2 - x1;
	float tangent = (dy / dx);
	
	if (x1 < x2){
		*xo = x1;
		*xf = x2;
		*yo = y1;
		*yf = y2;
	} else {
		*xo = x2;
		*xf = x1;
		*yo = y2;
		*yf = y1;
	}

	int result;
	if (tangent < 0){
		result = 1;
	} else {
		result = 0;
	}

	if (debug == 1){
		std::cout << "(" << x1 << ", " << y1 << ") -> (" << x2 << ", " << y2 << ")" << std::endl;
		std::cout << "Inverso: " << result;
		std::cout << " (" << *xo << ", " << *yo << ") -> (" << *xf << ", " << *yf << ")" << std::endl;
	}
	
	return result;
}

float GraphDrawer::calcAngle(int x1, int y1, int x2, int y2, int inverse){
	float angle = 0.0;

	float opposite = abs(y2 - y1);
	float adjacent = abs(x2 - x1);

	if (inverse == 1){
		opposite = y2 - y1;
		adjacent = x2 - x1;
	}

	angle = atan(opposite / adjacent);
	//float angleDec = Utils::toDeg(angle);
	return angle + (inverse * Utils::PI / 2);
}

float GraphDrawer::calcLength(int x1, int y1, int x2, int y2){
	float length = 0.0;

	float opposite = abs(x2 - x1);
	float adjacent = abs(y2 - y1);

	length = sqrt((opposite * opposite) + (adjacent * adjacent));
	return length;
}

float GraphDrawer::calcLength(SDL_Surface* surface, float angle){
	// TODO Implementar esto usando angle
	return (calcLength(0, 0, surface->w, surface->h));
}

void GraphDrawer::rotate(int x, int y, float cosAngle, float sinAngle, int* newX, int* newY){
	*newX = (x*cosAngle - y*sinAngle) + 0.5;
	*newY = (x*sinAngle + y*cosAngle) + 0.5;
}

int GraphDrawer::calcNewSize(int w, int h, float cosAngle, float sinAngle, int* newW, int* newH, int* maxYRes){
	int new00[2] = {0, 0};
	int newW0[2] = {0, 0};
	int new0H[2] = {0, 0};
	int newWH[2] = {0, 0};

	rotate(0, 0, cosAngle, sinAngle, &new00[X], &new00[Y]);
	rotate(w, 0, cosAngle, sinAngle, &newW0[X], &newW0[Y]);
	rotate(0, h, cosAngle, sinAngle, &new0H[X], &new0H[Y]);
	rotate(w, h, cosAngle, sinAngle, &newWH[X], &newWH[Y]);

	int minX = Utils::min(new00[X], newW0[X], new0H[X], newWH[X]);
	int maxX = Utils::max(new00[X], newW0[X], new0H[X], newWH[X]);

	int minY = Utils::min(new00[Y], newW0[Y], new0H[Y], newWH[Y]);
	int maxY = Utils::max(new00[Y], newW0[Y], new0H[Y], newWH[Y]);

	*newW = abs(maxX - minX);
	*newH = abs(maxY - minY);

	if (debug == 1){
		std::cout << "(0,0) -> (" << new00[X] << ", " << new00[Y] << ")" << std::endl;
		std::cout << "(w,0) -> (" << newW0[X] << ", " << newW0[Y] << ")" << std::endl;
		std::cout << "(0,h) -> (" << new0H[X] << ", " << new0H[Y] << ")" << std::endl;
		std::cout << "(w,h) -> (" << newWH[X] << ", " << newWH[Y] << ")" << std::endl;
	}

	*maxYRes = Utils::abs(new0H[Y]);
	return minX;
}

SDL_Surface* GraphDrawer::getSurfaceFor(float angle, SDL_Surface* sprite, int inverse){
	float cosAngle = cos(angle);
	float sinAngle = sin(angle);

	int newW, newH;
	int maxY;
	int minX = calcNewSize(sprite->w, sprite->h, cosAngle, sinAngle, &newW, &newH, &maxY);
	//float degAngle = Utils::toDeg(angle);

	SDL_Surface* rotatedSprite = SDL_CreateRGBSurface(sprite->flags, newW, newH, sprite->format->BitsPerPixel,
			sprite->format->Rmask, sprite->format->Gmask, sprite->format->Bmask, sprite->format->Amask);

	SDL_Surface* result = SDL_CreateRGBSurface(sprite->flags, newW, newH, sprite->format->BitsPerPixel,
			sprite->format->Rmask, sprite->format->Gmask, sprite->format->Bmask, sprite->format->Amask);

	makeTransparent(result, Color::white);
	fillSurface(result, Color::white);

	makeTransparent(rotatedSprite, Color::white);
	fillSurface(rotatedSprite, Color::white);

	int dx = -minX;
	int dy = 0;
	
	if (inverse == 1){
		dy = maxY;		
	}	

	if (debug == 1){
		std::cout << "W: " << sprite->w << " - H: " << sprite->h << std::endl; 				
		std::cout << "NewW: " << newW << " - NewH: " << newH << std::endl; 
	}

	for (int x = 0; x < sprite->w; x++){
		for (int y = 0; y < sprite->h; y++){
			//Uint32* srcColor;
			//srcColor = (Uint32*) sprite->pixels + y*sprite->pitch/4 + x;
			//Uint32* pixels = (Uint32 *)sprite->pixels;
			//srcColor = (Uint32*) pixels[ ( y * sprite->w ) + x ];

			int destX, destY;
			rotate(x, y, cosAngle, sinAngle, &destX, &destY);

			int finalX = destX + dx;
			int finalY = destY + dy;

			if (debug == 1){
				if (finalX < 0 || finalX >= newW){
					std::cout << "Undounded X: " << finalX << " (" << x << ", " << y << ") -> (" << destX << ", " << destY << ") "
						<< "dx = " << dx << std::endl;
				}

				if (finalY < 0 || finalY >= newH){
					std::cout << "Undounded Y: " << finalY << " (" << x << ", " << y << ") -> (" << destX << ", " << destY << ") "
						<< "dy = " << dy << std::endl;
				}
			}
			//drawPixel(rotatedSprite, finalX, finalY, *srcColor);
			drawIMG(sprite, x, y, 1, 1, finalX, finalY, rotatedSprite);
		}
	}

	drawIMG(rotatedSprite, 0, 0, result);
	if (inverse == 1){

	} else {
		float tangent = Utils::abs(tan(angle));
		if (tangent == 1){
			drawIMG(rotatedSprite, newW / 2, newH / 2, (newW / 2), (newH / 2), 0, 0, result);
			drawIMG(rotatedSprite, 0, 0, (newW / 2), (newH / 2), newW / 2, newH / 2, result);
		}
	}

	return result;
}

float GraphDrawer::calcXYRatio(SDL_Surface* surface){
	float w = surface->w;
	float h = surface->h;
	float ratio = w/h;
	return ratio;
}

int GraphDrawer::calcWidth(float length, float xyRatio){
	return length * xyRatio;
}

void GraphDrawer::calcNextXY(int i, int* x, int*y, int spriteW, int spriteH, float tanAngle, float angle, 
							 float XYRatio, int inverse){
	int dx = *x;
	int dy = *y;

	float coefY = 1;
	float coefX = 1;
	float fillCoef = 0.5;
	int xMoving = 0;
	int yMoving = 0;

	float angleDeg = Utils::toDeg(angle);

	if (angleDeg >= 0 && angleDeg <= 45){
		//if (inverse == 1){
		//	coefY = 1 + tanAngle;
		//} else {
			coefY = tanAngle;
			yMoving = 1;
		//}

	} else
		if (angleDeg > 45 && angleDeg < 90){
			//if (inverse == 1){
			//	coefX = (1 / tanAngle) + 1;
			//} else {
				coefX = 1 / tanAngle;
				xMoving = 1;
			//}
		} else 
			if (angleDeg >= 90 && angleDeg <= 135){
				coefX = -(1 / tan(angle));
				xMoving = 1;
		}
		else
			if (angleDeg > 135 && angleDeg <= 180){
				coefY = -tan(angle);
				yMoving = 1;
		}

	if (i > 0){
		dx = dx + (spriteW * coefX * fillCoef);			
		if (inverse == 1) {
				dy = dy - (spriteH * coefY * XYRatio * fillCoef);
		} else {
				dy = dy + (spriteH * coefY * XYRatio * fillCoef);
		}			
	}

	*x = dx;	
	if (i == 0){
		*y = dy - inverse * (spriteH / 2);
	} else {
		*y = dy;
	}
}

void GraphDrawer::drawSprite(SDL_Surface* sprite, int x1, int y1, int x2, int y2, SDL_Surface* backgroud){
	int xo, xf, yo, yf;

	int inverse = findXY(x1, y1, x2, y2, &xo, &xf, &yo, &yf);

	float angle = calcAngle(xo, yo, xf, yf, inverse);
	float angleDeg = Utils::toDeg(angle);
	float tanAngle = tan(angle);
	//float cosAngle = cos(angle);
	//float sinAngle = sin(angle);
	float length = calcLength(xo, yo, xf, yf);
	float realAngle = angle + (inverse * Utils::PI / 2);
	float realAngleDeg = angleDeg + (inverse * 90);

	SDL_Surface* rotatedSurface = getSurfaceFor(angle + (inverse * Utils::PI / 2), sprite, inverse);

	if(sprite != highway){		
		SDL_Surface* auxSurfaceP = getSurfaceFor(realAngle + ((2*Utils::PI)/360), sprite, inverse);
		drawIMG(auxSurfaceP,0,0,rotatedSurface);
		SDL_Surface* auxSurfaceN = getSurfaceFor(realAngle - ((2*Utils::PI)/360), sprite, inverse);	
		drawIMG(auxSurfaceN,0,0,rotatedSurface);
	}	

	float XYRatio = calcXYRatio(rotatedSurface);
	float spriteLength = calcLength(rotatedSurface, angle);
	//float spriteLength = sprite->w;
	
	if (angleDeg == 45 && inverse == 1) {
		spriteLength = spriteLength * 0.55;

	} else if (angleDeg > 45 && angleDeg < 90 && inverse == 1){
		spriteLength = spriteLength * 0.55;

	} else if (realAngleDeg > 45 && realAngleDeg <= 90) {
		spriteLength = spriteLength * 0.35;
	} else if (realAngleDeg >90 <= 145){
		spriteLength = spriteLength * 0.4655;
	} else if (realAngleDeg >= 270) {
		spriteLength = spriteLength * 0.6;
	} else {
			spriteLength = spriteLength * 0.45;
	}	

	if (length > 400){
		spriteLength = spriteLength * 0.9455;
	} else if (length > 300){
		spriteLength = spriteLength * 0.90;
	}

	int spriteW = rotatedSurface->w;
	int spriteH = rotatedSurface->h;

	int q = length / spriteLength;
	float mod = length - (spriteLength * q);

	int i;

	int x = xo;
	int y = yo;

	for (i = 0; i < q; i++){
		calcNextXY(i, &x, &y, spriteW, spriteH, tanAngle, angle + (inverse * Utils::PI / 2), XYRatio, inverse);
		if (debug == 1){
			std::cout << "X: " << x << std::endl;
			std::cout << "Y: " << y << std::endl;
		}
		drawIMG(rotatedSurface, 0, 0, spriteW, spriteH, x, y, backgroud);
	}

	if (mod > 0){
		calcNextXY(i, &x, &y, spriteW, spriteH, tanAngle, angle + (inverse * Utils::PI / 2), XYRatio, inverse);
		if (inverse == 1){
			drawIMG(rotatedSurface, 0, 0, mod * cos(realAngle), spriteH, x, y, backgroud);
		} else {
			drawIMG(rotatedSurface, 0, 0, mod * cos(angle), mod * sin(angle), x, y, backgroud);
		}
	}

	SDL_Flip(backgroud);
}

int GraphDrawer::getRealX(float x){
	int realX = x;
	int minimumX = xMin;
	return realX - minimumX;
}

int GraphDrawer::getRealY(float y){
	int realY = y;
	int minimumY = yMin;
	return realY - minimumY;
}

SDL_Surface* GraphDrawer::getTextureFor(Edge* e, float angle){
	std::string s = e->getWayType();
	if (angle == 0.0){
		if (strcmp(s.c_str(), "calle") == 0){
			return street;
		}
		if (strcmp(s.c_str(), "avenida") == 0){
			return avenue;
		}
		if (strcmp(s.c_str(), "autopista") == 0){
			return highway;
		}
	}

	if (angle == 90.0){
		if (strcmp(s.c_str(), "calle") == 0){
			return streetV;
		}
		if (strcmp(s.c_str(), "avenida") == 0){
			return avenueV;
		}
		if (strcmp(s.c_str(), "autopista") == 0){
			return highwayV;
		}
	}
	return NULL;
}

SDL_Surface* GraphDrawer::getSurfaceFor(string type) {
	if (type == "hotel") return hotel;
	if (type == "restaurant") return restaurant;
	if (type == "comisaria") return comisaria;
	if (type == "escuela") return escuela;
	if (type == "hospital") return hospital;
	return NULL;
}

float GraphDrawer::getFactor(float a, float b, int c, int d) {
	float difPos = Utils::abs(b - a);
	float difAdd = Utils::abs(d - c);
	float div = difPos/difAdd;
	return div;
}

void GraphDrawer::drawEdge(Edge* e, Vertex* origin, Vertex* destination){	
	if (origin->getX() == destination->getX()){

		float length = Utils::abs(origin->getY() - destination->getY());

		SDL_Surface* texture = getTextureFor(e, 90.0);
		if (texture != NULL){
			float minY = origin->getY();

			if (minY > destination->getY()) {
				minY = destination->getY();
			}			
			drawSpriteV (texture, getRealX (origin->getX()), 
				getRealY(minY) + crossroads->h, texture->w, length - crossroads->h, screen);
		}

	} else if (origin->getY() == destination->getY()){
		float length = Utils::abs(origin->getX() - destination->getX());
		SDL_Surface* texture = getTextureFor(e, 0.0);
		if (texture != NULL){
			float minX = origin->getX();

			if (minX > destination->getX()) {
				minX = destination->getX();
			}			
			drawSpriteH (texture, getRealX (minX) + crossroads->w, 
				getRealY(origin->getY()), length - crossroads->w, texture->h, screen);
		}
	} else {
		drawSprite(getTextureFor(e, 0.0), getRealX(origin->getX()), getRealY(origin->getY()),
			getRealX(destination->getX()), getRealY(destination->getY()), screen);
	}
}

void GraphDrawer::drawEdges(Graph* g, Vertex *origin){
	for (int i = 0; i < origin->getEdgesList()->getSize(); i++) {
		EdgeNode* node = (EdgeNode*) origin->getEdgesList()->get(i);		
		Edge* e =  node->getNodeValue();		
		Vertex* destination = g->getVertex(e->getIdTo());
		drawEdge(e, origin, destination);
	}
}

void GraphDrawer::drawVertexesAndEdges(Graph *g){
	for (int i = 0; i < g->getVertexQty(); i++) {
		VertexNode* node = (VertexNode*) g->getVertexList()->get(i);
		Vertex* v =  node->getNodeValue();		
		drawSpriteH(crossroads, getRealX(v->getX()), getRealY(v->getY()), crossroads->w, crossroads->h, screen);
		drawEdges(g, v);
	}	
}

void GraphDrawer::drawObjects(Map* map) {
	for (int i = 0; i < map->getMapObjectsList()->getSize(); i++) {
		MapObjectNode* mapObjectNode = (MapObjectNode*) map->getMapObjectsList()->get(i);
		MapObject* mapObject = mapObjectNode->getNodeValue();
		string edgeId = mapObject->getIdEdge();
		Edge* edge = map->getGraph()->getEdge(edgeId);
		if (edge != NULL) { //ya esta validado asi que deberia ser siempre distinto de NULL
			string idFrom = edge->getIdFrom();
			string idTo = edge->getIdTo();
			Vertex* from = map->getGraph()->getVertex(idFrom);
			Vertex* to = map->getGraph()->getVertex(idTo);
			float xFrom = from->getX();
			float yFrom = from->getY();
			float xTo = to->getX();
			float yTo = to->getY();
			float factorX = getFactor(xFrom,xTo,edge->getInitAddress(),edge->getLastAddress());
			float factorY = getFactor(yFrom,yTo,edge->getInitAddress(),edge->getLastAddress());
			float x0 = min(xFrom,xTo);
			float y0 = min(yFrom,yTo);
			int number = mapObject->getNumber();
			float posX = x0;		
			float posY = y0;
			SDL_Surface* texture = getSurfaceFor(mapObject->getType());
			float angle = calcAngle(xFrom,yFrom,xTo,yTo,0);
			//float degAngle = Utils::toDeg(angle);
			SDL_Surface* texture2 = getSurfaceFor(angle,texture,0);
			bool esPar = Utils::esPar(number);
			calcObjectPos(posX,posY,xFrom,xTo,yFrom,yTo,factorX,factorY,edge->getInitAddress(),edge->getLastAddress(),number,esPar);
			posX = Utils::round(posX);
			posY = Utils::round(posY);
			drawIMG(texture2,posX,posY,screen);
		}
	}
}

SDL_Surface* GraphDrawer::drawGraph(Map* map){
	
	searchMaxAndMin(map->getGraph());
	// Initialize SDL with best video mode
	if (SDL_Init(SDL_INIT_VIDEO) < 0){
		std::cout << "Could not initialize video\n";
	} else {
		const SDL_VideoInfo* info = SDL_GetVideoInfo();
		int vidFlags = SDL_GL_DOUBLEBUFFER;
		if (info->hw_available == 0) {
			vidFlags |= SDL_SWSURFACE;
		} else {
			vidFlags |= SDL_HWSURFACE;
		}
		//int bpp = info->vfmt->BitsPerPixel;
		// Esta seria el mapa entero sin mostrar por pantalla que guardamos en memoria
		screen = SDL_CreateRGBSurface(SDL_HWSURFACE, 1024, 768, 32, 0, 0, 0, 0);
		initImages();

		Color c(0,100,0);
		fillSurfaceWithTexture(screen, this->grass);
		//fillSurface(screen, c);
		drawVertexesAndEdges(map->getGraph());
		drawObjects(map);

		return screen;
	}

	return NULL;
}

void GraphDrawer::drawLine(SDL_Surface *screen, float xo, float yo, float xf, float yf ){
	Color w = w.red;
	//Correction factor to center the line
	int deviation = 20;
	
	if(xo == 0.0) xo += 1.0;
	if(xf == 0.0) xf += 1.0;
	if(yo == 0.0) yo += 1.0;
	if(yf == 0.0) yf += 1.0;

	if(xo == xf){
		if(yf<yo){
			for(int i = (int)yf; i < yo; i++){
			drawPixel(screen,(int)xo + deviation,i + deviation,w);
			drawPixel(screen,(int)xo + deviation,i+1 + deviation,w);
			drawPixel(screen,(int)xo + deviation,i+2 + deviation,w);
		}
		}else{
			for(int i = (int)yo; i < yf; i++){
				drawPixel(screen,(int)xo + deviation,i + deviation,w);
				drawPixel(screen,(int)xo + deviation,i+1 + deviation,w);
				drawPixel(screen,(int)xo + deviation,i+2 + deviation,w);
			}
		}
		return;
	}

	if(yo == yf){
		if(xf < xo){
			for(int i = (int)xf; i < xo; i++){
			drawPixel(screen,i + deviation,(int)yo + deviation,w);
			drawPixel(screen,i+1 + deviation,(int)yo + deviation,w);
			drawPixel(screen,i+2 + deviation,(int)yo + deviation,w);
		}
		}else{
			for(int i = (int)xo; i < xf; i++){
				drawPixel(screen,i + deviation,(int)yo + deviation,w);
				drawPixel(screen,i+1 + deviation,(int)yo + deviation,w);
				drawPixel(screen,i+2 + deviation,(int)yo + deviation,w);
			}
		}
		return;
	}
	float aux;
	
	float fX = xf;
	float fY = yf;

	float m;

	float yVal;
	int yInt; 
	float b;

	if((xf > xo && yf <  yo) || (xf < xo && yf > yo)){
		if((xf < xo && yf > yo)){
			aux = xo;
			xo = xf;
			xf = aux;
			aux = yo;
			yo = yf;
			yf = aux;
		}
		fX = (-xf+xo);
		fY = (-yf+yo);
	
		m = (fY/fX);

		b = (yf-(m*xf));
		for(int i= (int)xf; i > xo; i--){
			float yVal = m*i + b;
			int yInt = (int)yVal;
			drawPixel(screen,i + deviation,yInt + deviation,w);
			drawPixel(screen,i+1 + deviation,yInt + deviation,w);
			drawPixel(screen,i+2 + deviation,yInt + deviation,w);
		}
		return;
	}
	
	
	if(xo > xf && yo > yf){
		aux = xo;
		xo = xf;
		xf = aux;
		aux = yo;
		yo = yf;
		yf = aux;
	}
	fX = (xf-xo);
	fY = (yf-yo);
	
	m = (fY/fX);

	b = (yo-(m*xo));

	for(int i = (int)xo; i < xf; i++){
		yVal = m*i + b;
		
		yInt = (int)yVal;
		drawPixel(screen,i + deviation,yInt + deviation,w);
		drawPixel(screen,i+1 + deviation,yInt + deviation,w);
		drawPixel(screen,i+2 + deviation,yInt + deviation,w);
	}

}

void GraphDrawer::searchMaxAndMin(Graph *graph){
	for (int i = 0; i < graph->getVertexQty(); i++) {
		VertexNode* node = (VertexNode*) graph->getVertexList()->get(i);
		Vertex* v =  node->getNodeValue();
		float xo =  v->getX();
		float yo =	v->getY();
		if(xo < getXMin()){
			xMin = xo;
		}
		if(yo < getYMin()){
			yMin = yo;
		}
		if(xo > getXMax()){
			xMax = xo;
		}
		if(yo > getYMax()){
			yMax = yo;
		}
	}
}

float GraphDrawer::getXMin()const{
	return xMin;
}

float GraphDrawer::getYMin()const{
	return yMin;
}
float GraphDrawer::getXMax()const{
	return xMax;
}

float GraphDrawer::getYMax()const{
	return yMax;
}

float GraphDrawer::fixXPosition(float point){
	return point - getXMin();
}

float GraphDrawer::fixYPosition(float point){
	return point - getYMin();
}

void GraphDrawer::calcObjectPos(float& x, float& y,float x0, float xf, float y0, float yf, float factorX, float factorY, int init, int last, int number, bool esPar) {
	float xDeviationPos = 33;
	float xDeviationNeg = 25;
	float yDeviationPos = 33;
	float yDeviationNeg = 25;
	//horizontales
	if (y0 == yf) {
		if (x0 < xf) {
			x = x + (factorX * abs(number - init));

			if (init < last) {
				if (esPar) {
					y = y + yDeviationPos;
				}
				else {
					y = y - yDeviationNeg;
				}
			}
			else {
				if (esPar) {
					y = y - yDeviationNeg;
				}
				else {
					y = y + yDeviationPos;
				}
			}
		}
		else { //(x0 > xf)
			x = x + (factorX * abs(last - number));
			if (init < last) {
				if (esPar) {
					y = y - yDeviationNeg;
				}
				else {
					y = y + yDeviationPos;
				}
			}
			else {
				if (esPar) {
					y = y + yDeviationPos;
				}
				else {
					y = y - yDeviationNeg;
				}
			}
		}
	}
	//verticales
	else if (x0 == xf) {
		if (y0 < yf) {
			y = y + (factorY * abs(number - init));
			if (init < last) {
				if (esPar) {
					x = x - xDeviationNeg;
				}
				else {
					x = x + xDeviationPos;
				}
			}
			else {
				if (esPar) {
					x = x + xDeviationPos;
				}
				else {
					x = x - xDeviationNeg;
				}
			}
		}
		else {//(y0 > yf)
			y = y + (factorY * abs(last - number));
			if (init < last) {
				if (esPar) {
					x = x + xDeviationPos;
				}
				else {
					x = x - xDeviationNeg;
				}
			}
			else {
				if (esPar) {
					x = x - xDeviationNeg;
				}
				else {
					x = x + xDeviationPos;
				}
			}
		}
	}
	//diagonales
	else if (x0 > xf) {
		float angle = calcAngle(x0,y0,xf,yf,0);
		float degAngle = Utils::toDeg(angle);
		float moveX = 0.0;
		float moveY = 0.0;
		if ((0 < degAngle) && (degAngle < 60)) moveY = 1.0;
		if ((30 < degAngle) && (degAngle < 90)) moveX = 1.0;
				
		x = x + (factorX * abs(last - number));
		if (y0 < yf) {
			y = y + (factorY * abs(number - init));
			if (init < last) {
				if (esPar) {
					x = x - (xDeviationNeg * moveX);
					y = y - (yDeviationNeg * moveY);
				}
				else {
					x = x + (xDeviationPos * moveX);
					y = y + (yDeviationPos * moveY);
				}
			}
			else {
				if (esPar) {
					x = x + (xDeviationPos * moveX);
					y = y + (yDeviationPos * moveY);
				}
				else {
					x = x - (xDeviationNeg * moveX);
					y = y - (yDeviationNeg * moveY);
				}
			}
		}
		else {//(y0 > yf)
			y = y + (factorY * abs(last - number));
			if (init < last) {
				if (esPar) {
					x = x + (xDeviationPos * moveX);
					y = y - (yDeviationNeg * moveY);
				}
				else {
					x = x - (xDeviationNeg * moveX);
					y = y + (yDeviationPos * moveY);
				}
			}
			else {
				if (esPar) {
					x = x - (xDeviationNeg * moveX);
					y = y + (yDeviationPos * moveY);
				}
				else {
					x = x + (xDeviationPos * moveX);
					y = y - (yDeviationNeg * moveY);
				}
			}
		}
	}
	else { //(x0 < xf)
		float angle = calcAngle(x0,y0,xf,yf,0);
		float degAngle = Utils::toDeg(angle);
		int moveX = 0;
		int moveY = 0;
		if (0 < degAngle < 60) moveY = 1;
		if (30 < degAngle < 90) moveX = 1;

		x = x + (factorX * abs(number - init));
		if (y0 < yf) {
			y = y + (factorY * abs(number - init));
			if (init < last) {
				if (esPar) {
					x = x - (xDeviationNeg * moveX);
					y = y + (yDeviationPos * moveY);
				}
				else {
					x = x + (xDeviationPos * moveX);
					y = y - (yDeviationNeg * moveY);
				}
			}
			else {
				if (esPar) {
					x = x + (xDeviationPos * moveX);
					y = y - (yDeviationNeg * moveY);
				}
				else {
					x = x - (xDeviationNeg * moveX);
					y = y + (yDeviationPos * moveY);
				}
			}
		}
		else {//(y0 > yf)
			y = y + (factorY * abs(last - number));
			if (init < last) {
				if (esPar) {
					x = x + (xDeviationPos * moveX);
					y = y + (yDeviationPos * moveY);
				}
				else {
					x = x - (xDeviationNeg * moveX);
					y = y - (yDeviationNeg * moveY);
				}
			}
			else {
				if (esPar) {
					x = x - (xDeviationNeg * moveX);
					y = y - (yDeviationNeg * moveY);
				}
				else {
					x = x + (xDeviationPos * moveX);
					y = y + (yDeviationPos * moveY);
				}
			}
		}
	}	
	x = getRealX(x);
	y = getRealY(y);
}

SDL_Surface* GraphDrawer::getOriginDot() {
	return this->originDot;
}

SDL_Surface* GraphDrawer::getDestinyDot() {
	return this->destinyDot;
}
